#include "error.h"

#include <errno.h>

namespace sfc::io {

auto Error::to_str() const -> Str {
#define CASE(E) \
  case E:       \
    return #E
  switch (kind) {
    CASE(NotFound);
    CASE(PermissionDenied);
    CASE(ConnectionRefused);
    CASE(ConnectionReset);
    CASE(ConnectionAborted);
    CASE(NotConnected);
    CASE(AddrInUse);
    CASE(AddrNotAvailable);
    CASE(BrokenPipe);
    CASE(AlreadyExists);
    CASE(WouldBlock);
    CASE(InvalidInput);
    CASE(InvalidData);
    CASE(TimedOut);
    CASE(WriteZero);
    CASE(Interrupted);
    CASE(UnexpectedEof);
    CASE(Other);
  }
  return "Unknown";
}

auto Error::from_os_error(int code) -> Error {
  switch (code) {
    case EPERM:
      return Error::PermissionDenied;
    case ENOENT:
      return Error::NotFound;
    case EINTR:
      return Error::Interrupted;
    case EWOULDBLOCK:  // EAGAIN
      return Error::WouldBlock;
    case EACCES:
      return Error::PermissionDenied;
    case EEXIST:
      return Error::AlreadyExists;
    case EINVAL:
      return Error::InvalidInput;
    case EPIPE:
      return Error::BrokenPipe;
    case EADDRNOTAVAIL:
      return Error::AddrNotAvailable;
    case ENOTCONN:
      return Error::NotConnected;
    case ECONNABORTED:
      return Error::ConnectionAborted;
    case ECONNRESET:
      return Error::ConnectionReset;
    case EADDRINUSE:
      return Error::AddrInUse;
    case ETIMEDOUT:
      return Error::TimedOut;
    case ECONNREFUSED:
      return Error::ConnectionRefused;
    default:
      break;
  };
  return Error::Other;
}

auto Error::last_os_error() -> Error {
  return Error::from_os_error(errno);
}

}  // namespace sfc::io
